/*
 * debug_printf.c
 *
 *  Created on: 2022年02月22日
 *      Author: guyadong
 */
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include "debug_printf.h"
#ifndef COMMON_DBG_WITH_TIMESTAMP
#if HAS_TIME_H
#define COMMON_DBG_WITH_TIMESTAMP 1
#else
#define COMMON_DBG_WITH_TIMESTAMP 0
#endif
#endif
#if COMMON_DBG_WITH_TIMESTAMP
#define _TMPREFIX "%s "
#else
#define _TMPREFIX "%s"
#endif
#if HAS_TIME_H
#include <time.h>
#endif
uint32_t dbg_debuglog = 0;
char*  dbg_errbuf;
size_t dbg_errbufsz;
void dbg_define_err_buf(char * _errbuf, size_t _errbufsz)
{
	dbg_errbuf = _errbuf;
	dbg_errbufsz = _errbufsz;
}

void dbg_set_debuglog(uint32_t _debuglog)
{
	dbg_debuglog = _debuglog;
}
/************************************************************************/
/* 从路径中提取文件名                                                   */
/************************************************************************/
static const char* base_name(const char* file)
{
	const char*name = NULL;
	if (file)
	{
		name = strrchr(file, '/');
		if (!name)
		{
#if WIN32
			name = strrchr(file, '\\');
			if (!name)
			{
				name = file;
			}
#else
			name = file;
#endif
		}
		if (name < (file + strlen(file) - 1))
		{
			/** 跳过分割符  */
			name += 1;
		}
	}
	return name;
}
/************************************************************************/
/* 生成时间戳字符串                                                     */
/************************************************************************/
static void strtime_now(char *time_buf,size_t bufsz)
{
#if COMMON_DBG_WITH_TIMESTAMP
	if (time_buf && bufsz)
	{
		time_t _t = time(NULL);
		size_t rc = strftime(time_buf, bufsz, "%Y/%m/%d %H:%M:%S", gmtime(&_t));
	}
#else
	if (time_buf && bufsz)
	{
		time_buf[0] = '\0';
	}	
#endif
}
int _dbg_debug_vsnprintf(char* buf, size_t bufsz, const char* file, const char* fun, int line, const char* fmt, va_list args)
{
	if (NULL == buf || 0 == bufsz)
	{
		return 0;
	}
	const char*name = base_name(file);
	char time_buf[32] = { 0 };
	strtime_now(time_buf, sizeof(time_buf));
	/** 格式化输出文件名:函数名:行号的长度 */
	int srcinfosz = 0;
	/************************************************************************/
	/* 先向输出调试文件名,函数名,行号,返回值作为输出fmt的偏移量             */
	/************************************************************************/
	if (name && fun)
	{
		/** __FILE__:__FUNCTION__:__LINE__ */
		srcinfosz = snprintf(buf, bufsz, _TMPREFIX"%s:%s:%d ", time_buf, name, fun, line);
	}
	else if (name)
	{
		/** __FILE__:__LINE__ */
		srcinfosz = snprintf(buf, bufsz, _TMPREFIX"%s:%d ", time_buf, name, line);
	}
	else
	{
		/** __FUNCTION__:__LINE__ */
		srcinfosz = snprintf(buf, bufsz, _TMPREFIX"%s:%d ", time_buf, fun, line);
	}
	/** 向缓存区输出时会有输出长度超出缓冲区大小的可能,所以输出溢出则返回  */
	if (srcinfosz < 0 || srcinfosz >= bufsz)
	{
		return srcinfosz;
	}
	int c;
	if ((size_t)srcinfosz < bufsz)
	{
		/************************************************************************/
		/* 如果指定了输出缓冲区则向缓冲区输出                                   */
		/* 从 srcinfosz 指定的偏移开始输出,以拼接到前面输出的文件名:行号        */
		/************************************************************************/
		size_t remainsz = bufsz - (size_t)srcinfosz;
		c = vsnprintf(buf + srcinfosz, remainsz, fmt, args);
		if (c < 0 || c >= remainsz)
		{
			/** 输出长度溢出,则c为缓冲区长度 */
			c = (int)bufsz;
		}
		else
		{
			/* c 为向 buf 输出的总长度 */
			c += srcinfosz;
		}
	}
	else
	{
		/* 缓冲区没有容量用于输出,则c为前面输出的文件名:行号长度 */
		c = srcinfosz;
	}
	/** 确保'\0'结尾 */
	buf[bufsz - 1] = '\0';
	/** 返回 vsnprintf 或 vprintf 返回值 */
	return c;
}
int _dbg_debug_snprintf(char* buf, size_t bufsz, const char* file, const char* fun, int line, const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	int c;
	c = _dbg_debug_vsnprintf(buf, bufsz, file, fun, line, fmt, args);
	va_end(args);
	return c;
}
#if COMMON_DBG_USE_MMU
int _dbg_debug_vprintf_(const char* file, const char* fun, int line, const char* fmt, va_list args)
{
	const char*name = base_name(file);
	char time_buf[32] = { 0 };
	strtime_now(time_buf, sizeof(time_buf));
	/************************************************************************/
	/* 计算输出格式字符串长度                                               */
	/************************************************************************/
	size_t fmtsz = 0;
	if (name && fun)
	{
		/** __FILE__:__FUNCTION__:__LINE__ */
		fmtsz = 1 + snprintf(NULL, 0, "%s %s:%s:%d %s\n", time_buf, name, fun, line, fmt);
	}
	else if (name)
	{
		/** __FILE__:__LINE__ */
		fmtsz = 1 + snprintf(NULL, 0, "%s %s:%d %s\n", time_buf, name, line, fmt);
	}
	else
	{
		/** __FUNCTION__:__LINE__ */
		fmtsz = 1 + snprintf(NULL, 0, "%s %s:%d %s\n", time_buf, fun, line, fmt);
	}
	char* logfmt = (char*)malloc(fmtsz);
	if (logfmt)
	{
		/************************************************************************/
		/* 内存分配成功                                                         */
		/* 重新生成一个包含__FILE__,__FUNCTION__,__LINE__的format字符串         */
		/************************************************************************/
		if (name && fun)
		{
			/** __FILE__:__FUNCTION__:__LINE__ */
			snprintf(logfmt, fmtsz, "%s %s:%s:%d %s\n", time_buf, name, fun, line, fmt);
		}
		else if (name)
		{
			/** __FILE__:__LINE__ */
			snprintf(logfmt, fmtsz, "%s %s:%d %s\n", time_buf, name, line, fmt);
		}
		else
		{
			/** __FUNCTION__:__LINE__ */
			snprintf(logfmt, fmtsz, "%s %s:%d %s\n", time_buf, fun, line, fmt);
		}
		int c;
		/************************************************************************/
		/* 向标准控制台输出                                                     */
		/************************************************************************/
		c = COMMON_DEBUG_VPRINTF(logfmt, args);
		/** 释放申请的内存 */
		free(logfmt);
		/** 返回 vsnprintf 或 vprintf 返回值 */
		return c;
	}
	else
	{
		/************************************************************************/
		/* 内存分配失败则不能输出__FILE__,__FUNCTION__,__LINE__                 */
		/************************************************************************/
		int c;
		/************************************************************************/
		/* 向标准控制台输出                                                     */
		/************************************************************************/
		c = COMMON_DEBUG_VPRINTF(fmt, args);
		/** 返回 vsnprintf 或 vprintf 返回值 */
		return c;
	}
}
#else
int _dbg_debug_vprintf_(const char* file, const char* fun, int line, const char* fmt, va_list args)
{
	const char*name = base_name(file);
	/************************************************************************/
	/* 生成时间戳字符串                                                     */
	/************************************************************************/
	char time_buf[32] = { 0 };
	strtime_now(time_buf, sizeof(time_buf));
	/** 格式化输出文件名:函数名:行号的长度 */
	int srcinfosz = 0;
	/************************************************************************/
	/* 先向输出调试文件名,函数名,行号,返回值作为输出fmt的偏移量             */
	/************************************************************************/
	if (name && fun)
	{
		/** __FILE__:__FUNCTION__:__LINE__ */
		srcinfosz = COMMON_DEBUG_PRINTF(_TMPREFIX"%s:%s:%d ", time_buf, name, fun, line);
	}
	else if (name)
	{
		/** __FILE__:__LINE__ */
		srcinfosz = COMMON_DEBUG_PRINTF(_TMPREFIX"%s:%d ", time_buf, name, line);
	}
	else
	{
		/** __FUNCTION__:__LINE__ */
		srcinfosz = COMMON_DEBUG_PRINTF(_TMPREFIX"%s:%d ", time_buf, fun, line);
	}
	int c;
	c = COMMON_DEBUG_VPRINTF(fmt, args);
	/* c 为向 buf 输出的总长度 */
	c += srcinfosz;
	COMMON_DEBUG_PRINTF("\n");
	c++;
	/** 返回 vsnprintf 或 vprintf 返回值 */
	return c;
}
#endif
int _dbg_debug_printf_(const char* file, const char* fun, int line, const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	int wsz = _dbg_debug_vprintf_(file, fun, line, fmt, args);
	va_end(args);
	return wsz;
}
int _dbg_debug_printf(char* buf, size_t bufsz, const char* file, const char* fun, int line, const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	int wsz;
	if (buf && bufsz)
	{
		wsz = _dbg_debug_vsnprintf(buf, bufsz, file, fun, line, fmt, args);
	}
	else
	{
		wsz = _dbg_debug_vprintf_(file, fun, line, fmt, args);
	}
	va_end(args);
	return wsz;

}
#if COMMON_DBG_USE_MMU
char* dbg_strndump(const char* str, size_t size)
{
	size_t length = 0;
	char *copy = NULL;

	if (str == NULL)
	{
		return NULL;
	}
	if (0 == size)
	{
		size = strlen(str);
	}
	size_t slen = strlen(str);
	if (size > slen)
	{
		size = slen;
	}
	length = size + 1;
	copy = (char*)malloc(length);
	if (copy == NULL)
	{
		return NULL;
	}
	memcpy(copy, str, size);
	copy[size] = '\0';
	return copy;
}
char* dbg_buf_printf(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	size_t bufsz = 1 + vsnprintf(NULL, 0, fmt, args);
	char* buf = (char*)malloc(bufsz);
	if (buf)
	{
		vsnprintf(buf, bufsz, fmt, args);
	}
	va_end(args);
	return buf;
}
char* dbg_buf_vprintf(const char* fmt, va_list args)
{
	size_t bufsz = 1 + vsnprintf(NULL, 0, fmt, args);
	char* buf = (char*)malloc(bufsz);
	if (buf)
	{
		vsnprintf(buf, bufsz, fmt, args);
	}
	return buf;
}
void dbg_print_str(const char* file, const char* fun, int line,const char* msg,const char* input, size_t _start, size_t _end)
{
	if (input)
	{
		char * dump = dbg_strndump(input + _start, _end - _start);
		if (dump)
		{
			_dbg_debug_printf(NULL, 0, file, fun,line, "%s:<<%s>>", msg,dump);
			free(dump);
		}
		else 
		{
			_dbg_debug_printf(NULL, 0, file, fun, line, "%s",msg);
			COMMON_DEBUG_PRINTF("<<");
			for (size_t i = _start; i < _end; ++i)
			{
				printf("%c", input[i]);
			}
			COMMON_DEBUG_PRINTF(">>\n");
		}
	}
}
#endif
